use std::time::Duration;

use tokio::io::AsyncReadExt;

use crate::{error::AppErr, utils::{decode_u16, decode_u8, new_buf}};

use super::frame::Frame;

pub const READ_TIMEOUT: Duration = Duration::from_secs(10);

pub const MIN_FRAME_LEN: usize = 6;
pub const HEAD: u16 = 0xE11E;

pub async fn read_frame<R: AsyncReadExt + Unpin>(r: &mut R) -> Result<Frame, AppErr> {

    let mut buf = [0u8; 6];

    r.read_exact(&mut buf).await?;

    let head = decode_u16(&buf);
    if head != HEAD {
        return Err(AppErr::TcpProto("head is invalid"));
    }

    let size = decode_u16(&buf[2..]) as usize;
    if size < MIN_FRAME_LEN {
        return Err(AppErr::TcpProto("len is invalid"));
    }

    let c_type = decode_u8(&buf[4..]);
    let seq = decode_u8(&buf[5..]);
    
    if size == MIN_FRAME_LEN {
        return Ok( Frame { c_type, seq, body: None } );
    }

    let mut data = new_buf(size - MIN_FRAME_LEN);
    r.read_exact(&mut data).await?;


    Ok( Frame { c_type, seq, body: Some(data) } )
}

